/*
* ============================================================================
*  Name        : sea_platform.h
*  Part of     : Finite state machine utilities
*  Description : 
*  Version     : %version: %
*  
*
* ============================================================================
*/
/**
 * @file sea_platform.h
 *
 * @ingroup StateMachineFramework
 */
#if !defined( __sea_platform_h__ )
#define __sea_platform_h__

/**
 * @file sea_platform.h
 * @brief
 *  Framework is based on the following platform primitives: sea::OsMutex, sea::OsSemaphore, sea::OsThread, sea::OsTime, sea::OsAtomic
 *
 * @ingroup Platforms
 */

#include "sea_consts.h"
#include "sea_config.h"
#include "sea_types.h"
#include "sea_object.h"

#define MAX_BUFFER 512
#define SEA_TRACE_ENTRY( ) SEA_TRACE( SEA_PRETTY_FUNCTION )

#if defined( SEA_PLATROM_TRACE )
    #define SEA_TRACE SEA_PLATROM_TRACE
#else
    #define SEA_TRACE sea::Trace::Print
#endif

#if defined( SEA_OS_QT )
    #include "sea_platform_qt.h"
#elif defined( SEA_OS_WIN32 )
    #include "sea_platform_win.h"
#elif defined( SEA_OS_LINUX )
    #include "sea_platform_posix.h"
#elif defined( SEA_OS_SOS )
    #include "sea_platform_sos.h"
#elif defined( SEA_OS_LESS )
    #include "sea_platform_less.h"
#endif

#include "sea_trace.h"

using namespace std;

namespace sea
{
    class OsSemaphore;
    class OsFastSemaphore;

    /** 
     * @class OsNotifier
     * @brief
     * Yet another syncronisation object. Many tell to one when they finished. @ref sea::OsSemaphore derivative.
     * @details
     *  One to many sinchronisation mechanism. One creates the object <br>
     *  and pass it around via reserve( ) interface.  <br>
     *   Example <br>
     * @code
     * void foo( )
     * {
     *      // Local reference will be destroyed by
     *      // wait( ) call
     *      OsNotifier* boss = NEW OsNotifier( );
     *
     *      int n = 100;
     *      for( int i = 0; i < n; i++ )
     *      {
     *          MyThread* thread = NEW MyThread( boss );
     *          obj->start( );
     *          thread->release_ref( );
     *      }
     * 
     *      // Wait for all threads to finish
     *      boss->wait( );
     * }
     *
     * class MyThread : public OsThread
     * {
     * public:
     *     MyThread( OsNotifier* it ) : m_it( it ) { it->reserve( ); }
     *     void exec( ) { m_it->release( ); }
     * private:
     *    OsNotifier* m_it;
     * };
     *
     * @endcode
     * @ingroup Platforms
     */
    class OsNotifier : public Object
    {
    public:
        OsNotifier( );
        ~OsNotifier( );

        void reserve( );
        void release( );
        void wait( );
        OsSemaphore* get( ){ return m_semaphore; }

    private:
        bool m_waiting;
        OsSemaphore* m_semaphore;
    };

    /** 
     * @class OsFastSemaphore
     * @brief Semaphore that goes to kernel side only on contention
     *  
     * @ingroup Platforms
     */
    class OsFastSemaphore : public OsSemaphore
    {
    public:
        OsFastSemaphore( int aInit = 0 ) : m_counter( aInit ), m_waiting( false ) { }

        void wait( int aInc = 1 )
        {
            m_lock.enter( );
            if ( m_counter == 0 )
            {
                m_waiting = true;
                m_lock.leave( );

                OsSemaphore::wait( aInc );

                m_lock.enter( );
            }

            m_counter--;
            m_lock.leave( );
        }

        void signal( int aDec = 1 )
        {
            m_lock.enter( );
            m_counter++;

            if ( m_waiting )
            {
                m_waiting = false;
                m_lock.leave( );

                OsSemaphore::signal( aDec );
            }
            else
            {
                m_lock.leave( );
            }
        }
    private:
        int m_counter;
        bool m_waiting;
        OsMutex m_lock;                 ///< Atomic operations guard. DO NOT use spinlock here!!!
                                        ///< it will be much slower!!!
    };

    // ----------------------------------------------------------------------------
    // OsMutex Scoped Ctor
    // ----------------------------------------------------------------------------
    inline OsMutex::Scoped::Scoped( OsMutex* critical_section, bool do_try ): m_mutex( critical_section ) 
    { 
        if ( m_mutex )
        {
            if ( !do_try )
            {
                m_mutex->enter( );
            }
            else
            if ( !m_mutex->try_enter( ) )
            {
                m_mutex = NULL;
            }
        }
    }

    // ----------------------------------------------------------------------------
    // OsMutex Scoped Dtor
    // ----------------------------------------------------------------------------
    inline OsMutex::Scoped::~Scoped( )
    { 
        if ( m_mutex )
        {
            m_mutex->leave( ); 
        }
    }
}

#endif // #if !defined( __sea_platform_h__ )

